const { EventEmitter } = require('events');
const http = require('http');
const crypto = require('crypto');

const OPCODES = {
    CONTINUE: 0,
    TEXT: 1, // 文本
    BINARY: 2, // 二进制
    CLOSE: 8,
    PING: 9,
    PONG: 10,
};

  

function hashKey(key) {
    const sha1 = crypto.createHash('sha1');
    sha1.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11');
    return sha1.digest('base64');
}


function handleMask(maskBytes, data) {
    const payload = Buffer.alloc(data.length);
    for (let i = 0; i < data.length; i++) {
      payload[i] = maskBytes[i % 4] ^ data[i];
    }
    return payload;
}


function encodeMessage(opcode, payload) {
    //payload.length < 126
    let bufferData = Buffer.alloc(payload.length + 2 + 0);;
    
    let byte1 = parseInt('10000000', 2) | opcode; // 设置 FIN 为 1
    let byte2 = payload.length;
  
    bufferData.writeUInt8(byte1, 0);
    bufferData.writeUInt8(byte2, 1);
  
    payload.copy(bufferData, 2);
    
    return bufferData;
}



//EventEmitter是Node.js中的一个核心模块，用于实现事件驱动编程。可以用于发布(emit) 和 监听(on)事件。
class MyWebsocket extends EventEmitter {
  constructor(options) {
    super(options);

    const server = http.createServer();
    server.listen(options.port || 8080);

    server.on('upgrade', (req, socket) => {
         this.socket = socket;
         socket.setKeepAlive(true);

         const resHeaders = [
            'HTTP/1.1 101 Switching Protocols',
            'Upgrade: websocket',
            'Connection: Upgrade',
            'Sec-WebSocket-Accept: ' + hashKey(req.headers['sec-websocket-key']),
            '',
            ''
          ].join('\r\n');
          socket.write(resHeaders);

          socket.on('data', (data) => {
             this.processData(data);  // 最终调用 this.emit('data','xxxx') 发送数据
          });

          socket.on('close', (error) => {
             this.emit('close');
          });

    });
  }



  handleRealData(opcode, realDataBuffer){
    switch (opcode) {
      case OPCODES.TEXT:
        this.emit('data', realDataBuffer.toString('utf8'));  //发送data,就要监听data
        break;
      case OPCODES.BINARY:
        this.emit('data', realDataBuffer);
        break;
      default:
        this.emit('close');  //发送close,就要监听close
        break;
    }
  }


  //解析数据
  processData(bufferData){
        const byte1 = bufferData.readUInt8(0);  // 读取 8 位无符号整数的内容，也就是一个字节的内容。参数是偏移的字节，这里是 0。
        let opcode = byte1 & 0x0f;              // 通过位运算取出后四位，这就是 opcode 了

        const byte2 = bufferData.readUInt8(1);  // 同上,偏移1，取的是第二个字节的内容
        const str2 = byte2.toString(2);
        const MASK = str2[0];
        let payloadLength = parseInt(str2.substring(1), 2);  // 也可用splice


        let curByteIndex = 2;  //当前处理到第几个字节。

        // 如果 7 位的内容是 126，那就不用它了，用后面的 16 位的内容作为 payload 长度
        if (payloadLength === 126) {
            payloadLength = bufferData.readUInt16BE(2);    //如果是 126，那就从第 3 个字节开始，读取 2 个字节也就是 16 位的长度，用 buffer.readUInt16BE 方法。
            curByteIndex += 2;
        // 如果 7 位的内容是 127，也不用它了，用后面那个 64 位的内容作为 payload 长度
        } else if (payloadLength === 127) {
            payloadLength = bufferData.readBigUInt64BE(2);   // 如果是 127，那就从第 3 个字节开始，读取 8 个字节也就是 64 位的长度，用 buffer.readBigUInt64BE 方法。
            curByteIndex += 8;
        }


        let realData = null;

        //截取payload数据
        if (MASK) {
            const maskKey = bufferData.slice(curByteIndex, curByteIndex + 4);  
            curByteIndex += 4;
            const payloadData = bufferData.slice(curByteIndex, curByteIndex + payloadLength);
            realData = handleMask(maskKey, payloadData);
        } else {
            realData = bufferData.slice(curByteIndex, curByteIndex + payloadLength);;
        }


        this.handleRealData(opcode, realData);
  }


  //发送执行
  doSend(opcode, bufferDatafer) {
     this.socket.write(encodeMessage(opcode, bufferDatafer));
  }

  //发送数据
  send(data) {
    let opcode;
    let buffer;

    if (Buffer.isBuffer(data)) {
        opcode = OPCODES.BINARY;
        buffer = data;
    } else if (typeof data === 'string') {
        opcode = OPCODES.TEXT;
        buffer = Buffer.from(data, 'utf8');
    } else {
        console.error('暂不支持发送的数据类型')
    }

    this.doSend(opcode, buffer);
  }





}





exports = module.exports = MyWebsocket;